home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / unix / tkUnixFont.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  27.1 KB  |  980 lines  |  [TEXT/CWIE]

  1. /*
  2.  * tkUnixFont.c --
  3.  *
  4.  *    Contains the Unix implementation of the platform-independant
  5.  *    font package interface.
  6.  *
  7.  * Copyright (c) 1996 Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * SCCS: @(#) tkUnixFont.c 1.15 97/05/19 13:48:45
  13.  */
  14.  
  15. #include "tkPort.h"
  16. #include "tkInt.h"
  17. #include "tkUnixInt.h"
  18.  
  19. #include "tkFont.h"
  20.  
  21. #ifndef ABS
  22. #define ABS(n)    (((n) < 0) ? -(n) : (n))
  23. #endif
  24.  
  25. /*
  26.  * The following structure represents Unix's implementation of a font.
  27.  */
  28.  
  29. typedef struct UnixFont {
  30.     TkFont font;        /* Stuff used by generic font package.  Must
  31.                  * be first in structure. */
  32.     Display *display;        /* The display to which font belongs. */
  33.     XFontStruct *fontStructPtr;    /* X information about font. */
  34.     char types[256];        /* Array giving types of all characters in
  35.                  * the font, used when displaying control
  36.                  * characters.  See below for definition. */
  37.     int widths[256];        /* Array giving widths of all possible
  38.                  * characters in the font. */
  39.     int underlinePos;        /* Offset from baseline to origin of
  40.                  * underline bar (used for simulating a native
  41.                  * underlined font). */
  42.     int barHeight;        /* Height of underline or overstrike bar
  43.                  * (used for simulating a native underlined or
  44.                  * strikeout font). */
  45. } UnixFont;
  46.  
  47. /*
  48.  * Possible values for entries in the "types" field in a UnixFont structure,
  49.  * which classifies the types of all characters in the given font.  This
  50.  * information is used when measuring and displaying characters.
  51.  *
  52.  * NORMAL:        Standard character.
  53.  * REPLACE:        This character doesn't print:  instead of
  54.  *            displaying character, display a replacement
  55.  *            sequence like "\n" (for those characters where
  56.  *            ANSI C defines such a sequence) or a sequence
  57.  *            of the form "\xdd" where dd is the hex equivalent
  58.  *            of the character.
  59.  * SKIP:        Don't display anything for this character.  This
  60.  *            is only used where the font doesn't contain
  61.  *            all the characters needed to generate
  62.  *            replacement sequences.
  63.  */ 
  64.  
  65. #define NORMAL        0
  66. #define REPLACE        1
  67. #define SKIP        2
  68.  
  69. /*
  70.  * Characters used when displaying control sequences.
  71.  */
  72.  
  73. static char hexChars[] = "0123456789abcdefxtnvr\\";
  74.  
  75. /*
  76.  * The following table maps some control characters to sequences like '\n'
  77.  * rather than '\x10'.  A zero entry in the table means no such mapping
  78.  * exists, and the table only maps characters less than 0x10.
  79.  */
  80.  
  81. static char mapChars[] = {
  82.     0, 0, 0, 0, 0, 0, 0,
  83.     'a', 'b', 't', 'n', 'v', 'f', 'r',
  84.     0
  85. };
  86.  
  87.  
  88. static UnixFont *    AllocFont _ANSI_ARGS_((TkFont *tkFontPtr,
  89.                 Tk_Window tkwin, XFontStruct *fontStructPtr,
  90.                 CONST char *fontName));
  91. static void        DrawChars _ANSI_ARGS_((Display *display,
  92.                 Drawable drawable, GC gc, UnixFont *fontPtr,
  93.                 CONST char *source, int numChars, int x,
  94.                 int y));
  95. static int        GetControlCharSubst _ANSI_ARGS_((int c, char buf[4]));
  96.  
  97.  
  98. /*
  99.  *---------------------------------------------------------------------------
  100.  *
  101.  * TkpGetNativeFont --
  102.  *
  103.  *    Map a platform-specific native font name to a TkFont.
  104.  *
  105.  * Results:
  106.  *     The return value is a pointer to a TkFont that represents the
  107.  *    native font.  If a native font by the given name could not be
  108.  *    found, the return value is NULL.  
  109.  *
  110.  *    Every call to this procedure returns a new TkFont structure,
  111.  *    even if the name has already been seen before.  The caller should
  112.  *    call TkpDeleteFont() when the font is no longer needed.
  113.  *
  114.  *    The caller is responsible for initializing the memory associated
  115.  *    with the generic TkFont when this function returns and releasing
  116.  *    the contents of the generic TkFont before calling TkpDeleteFont().
  117.  *
  118.  * Side effects:
  119.  *    None.
  120.  *
  121.  *---------------------------------------------------------------------------
  122.  */
  123.  
  124. TkFont *
  125. TkpGetNativeFont(tkwin, name)
  126.     Tk_Window tkwin;        /* For display where font will be used. */
  127.     CONST char *name;        /* Platform-specific font name. */
  128. {
  129.     XFontStruct *fontStructPtr;
  130.  
  131.     fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), name);
  132.     if (fontStructPtr == NULL) {
  133.     return NULL;
  134.     }
  135.  
  136.     return (TkFont *) AllocFont(NULL, tkwin, fontStructPtr, name);
  137. }
  138.  
  139. /*
  140.  *---------------------------------------------------------------------------
  141.  *
  142.  * TkpGetFontFromAttributes -- 
  143.  *
  144.  *    Given a desired set of attributes for a font, find a font with
  145.  *    the closest matching attributes.
  146.  *
  147.  * Results:
  148.  *     The return value is a pointer to a TkFont that represents the
  149.  *    font with the desired attributes.  If a font with the desired
  150.  *    attributes could not be constructed, some other font will be
  151.  *    substituted automatically.
  152.  *
  153.  *    Every call to this procedure returns a new TkFont structure,
  154.  *    even if the specified attributes have already been seen before.
  155.  *    The caller should call TkpDeleteFont() to free the platform-
  156.  *    specific data when the font is no longer needed.  
  157.  *
  158.  *    The caller is responsible for initializing the memory associated
  159.  *    with the generic TkFont when this function returns and releasing
  160.  *    the contents of the generic TkFont before calling TkpDeleteFont().
  161.  *
  162.  * Side effects:
  163.  *    None.
  164.  *
  165.  *---------------------------------------------------------------------------
  166.  */
  167. TkFont *
  168. TkpGetFontFromAttributes(tkFontPtr, tkwin, faPtr)
  169.     TkFont *tkFontPtr;        /* If non-NULL, store the information in
  170.                  * this existing TkFont structure, rather than
  171.                  * allocating a new structure to hold the
  172.                  * font; the existing contents of the font
  173.                  * will be released.  If NULL, a new TkFont
  174.                  * structure is allocated. */
  175.     Tk_Window tkwin;        /* For display where font will be used. */
  176.     CONST TkFontAttributes *faPtr;  /* Set of attributes to match. */
  177. {
  178.     int numNames, score, i, scaleable, pixelsize, xaPixelsize;
  179.     int bestIdx, bestScore, bestScaleableIdx, bestScaleableScore;
  180.     TkXLFDAttributes xa;    
  181.     char buf[256];
  182.     UnixFont *fontPtr;
  183.     char **nameList;
  184.     XFontStruct *fontStructPtr;
  185.     CONST char *fmt, *family;
  186.     double d;
  187.  
  188.     family = faPtr->family;
  189.     if (family == NULL) {
  190.     family = "*";
  191.     }
  192.  
  193.     pixelsize = -faPtr->pointsize;
  194.     if (pixelsize < 0) {
  195.         d = -pixelsize * 25.4 / 72;
  196.     d *= WidthOfScreen(Tk_Screen(tkwin));
  197.     d /= WidthMMOfScreen(Tk_Screen(tkwin));
  198.     d += 0.5;
  199.         pixelsize = (int) d;
  200.     }
  201.  
  202.     /*
  203.      * Replace the standard Windows and Mac family names with the names that
  204.      * X likes.
  205.      */
  206.  
  207.     if ((strcasecmp("Times New Roman", family) == 0)
  208.         || (strcasecmp("New York", family) == 0)) {
  209.     family = "Times";
  210.     } else if ((strcasecmp("Courier New", family) == 0)
  211.         || (strcasecmp("Monaco", family) == 0)) {
  212.     family = "Courier";
  213.     } else if ((strcasecmp("Arial", family) == 0)
  214.         || (strcasecmp("Geneva", family) == 0)) {
  215.     family = "Helvetica";
  216.     }
  217.  
  218.     /*
  219.      * First try for the Q&D exact match.  
  220.      */
  221.  
  222. #if 0
  223.     sprintf(buf, "-*-%.200s-%s-%c-normal-*-*-%d-*-*-*-*-iso8859-1", family,
  224.         ((faPtr->weight > TK_FW_NORMAL) ? "bold" : "medium"),
  225.         ((faPtr->slant == TK_FS_ROMAN) ? 'r' :
  226.             (faPtr->slant == TK_FS_ITALIC) ? 'i' : 'o'),
  227.         faPtr->pointsize * 10);
  228.     fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
  229. #else
  230.     fontStructPtr = NULL;
  231. #endif
  232.  
  233.     if (fontStructPtr != NULL) {
  234.     goto end;
  235.     }
  236.     /*
  237.      * Couldn't find exact match.  Now fall back to other available
  238.      * physical fonts.  
  239.      */
  240.  
  241.     fmt = "-*-%.240s-*-*-*-*-*-*-*-*-*-*-*-*";
  242.     sprintf(buf, fmt, family);
  243.     nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames);
  244.     if (numNames == 0) {
  245.     /*
  246.      * Try getting some system font.
  247.      */
  248.  
  249.     sprintf(buf, fmt, "fixed");
  250.     nameList = XListFonts(Tk_Display(tkwin), buf, 10000, &numNames);
  251.     if (numNames == 0) {
  252.         getsystem:
  253.         fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "fixed");
  254.         if (fontStructPtr == NULL) {
  255.         fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), "*");
  256.         if (fontStructPtr == NULL) {
  257.             panic("TkpGetFontFromAttributes: cannot get any font");
  258.         }
  259.         }
  260.         goto end;
  261.     }
  262.     }
  263.  
  264.     /*
  265.      * Inspect each of the XLFDs and pick the one that most closely
  266.      * matches the desired attributes.
  267.      */
  268.  
  269.     bestIdx = 0;
  270.     bestScore = INT_MAX;
  271.     bestScaleableIdx = 0;
  272.     bestScaleableScore = INT_MAX;
  273.  
  274.     for (i = 0; i < numNames; i++) {
  275.     score = 0;
  276.     scaleable = 0;
  277.     if (TkParseXLFD(nameList[i], &xa) != TCL_OK) {
  278.         continue;
  279.     }
  280.     xaPixelsize = -xa.fa.pointsize;
  281.     
  282.     /*
  283.      * Since most people used to use -adobe-* in their XLFDs,
  284.      * preserve the preference for "adobe" foundry.  Otherwise
  285.      * some applications looks may change slightly if another foundry
  286.      * is chosen.
  287.      */
  288.      
  289.     if (strcasecmp(xa.foundry, "adobe") != 0) {
  290.         score += 3000;
  291.     }
  292.     if (xa.fa.pointsize == 0) {
  293.         /*
  294.          * A scaleable font is almost always acceptable, but the
  295.          * corresponding bitmapped font would be better.
  296.          */
  297.  
  298.         score += 10;
  299.         scaleable = 1;
  300.     } else {
  301.         /*
  302.          * A font that is too small is better than one that is too
  303.          * big.
  304.          */
  305.  
  306.         if (xaPixelsize > pixelsize) {
  307.         score += (xaPixelsize - pixelsize) * 120;
  308.         } else { 
  309.         score += (pixelsize - xaPixelsize) * 100;
  310.         }
  311.     }
  312.  
  313.     score += ABS(xa.fa.weight - faPtr->weight) * 30;
  314.     score += ABS(xa.fa.slant - faPtr->slant) * 25;
  315.     if (xa.slant == TK_FS_OBLIQUE) {
  316.         /*
  317.          * Italic fonts are preferred over oblique. */
  318.  
  319.         score += 4;
  320.     }
  321.  
  322.     if (xa.setwidth != TK_SW_NORMAL) {
  323.         /*
  324.          * The normal setwidth is highly preferred.
  325.          */
  326.         score += 2000;
  327.     }
  328.     if (xa.charset == TK_CS_OTHER) {
  329.         /*
  330.          * The standard character set is highly preferred over
  331.          * foreign languages charsets (because we don't support
  332.          * other languages yet).
  333.          */
  334.         score += 11000;
  335.     }
  336.     if ((xa.charset == TK_CS_NORMAL) && (xa.encoding != 1)) {
  337.         /*
  338.          * The '1' encoding for the characters above 0x7f is highly
  339.          * preferred over the other encodings.
  340.          */
  341.         score += 8000;
  342.     }
  343.  
  344.     if (scaleable) {
  345.         if (score < bestScaleableScore) {
  346.         bestScaleableIdx = i;
  347.         bestScaleableScore = score;
  348.         }
  349.     } else {
  350.         if (score < bestScore) {
  351.         bestIdx = i;
  352.         bestScore = score;
  353.         }
  354.     }
  355.     if (score == 0) {
  356.         break;
  357.     }
  358.     }
  359.  
  360.     /*
  361.      * Now we know which is the closest matching scaleable font and the
  362.      * closest matching bitmapped font.  If the scaleable font was a
  363.      * better match, try getting the scaleable font; however, if the
  364.      * scalable font was not actually available in the desired
  365.      * pointsize, fall back to the closest bitmapped font.
  366.      */
  367.  
  368.     fontStructPtr = NULL;
  369.     if (bestScaleableScore < bestScore) {
  370.     char *str, *rest;
  371.     
  372.     /*
  373.      * Fill in the desired pointsize info for this font.
  374.      */
  375.  
  376.     tryscale:
  377.     str = nameList[bestScaleableIdx];
  378.     for (i = 0; i < XLFD_PIXEL_SIZE - 1; i++) {
  379.         str = strchr(str + 1, '-');
  380.     }
  381.     rest = str;
  382.     for (i = XLFD_PIXEL_SIZE - 1; i < XLFD_REGISTRY; i++) {
  383.         rest = strchr(rest + 1, '-');
  384.     }
  385.     *str = '\0';
  386.     sprintf(buf, "%.240s-*-%d-*-*-*-*-*%s", nameList[bestScaleableIdx],
  387.         pixelsize, rest);
  388.     *str = '-';
  389.     fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
  390.     bestScaleableScore = INT_MAX;
  391.     }
  392.     if (fontStructPtr == NULL) {
  393.     strcpy(buf, nameList[bestIdx]);
  394.     fontStructPtr = XLoadQueryFont(Tk_Display(tkwin), buf);
  395.     if (fontStructPtr == NULL) {
  396.         /*
  397.          * This shouldn't happen because the font name is one of the
  398.          * names that X gave us to use, but it does anyhow.
  399.          */
  400.  
  401.         if (bestScaleableScore < INT_MAX) {
  402.         goto tryscale;
  403.         } else {
  404.         XFreeFontNames(nameList);
  405.         goto getsystem;
  406.         }
  407.     }
  408.     }
  409.     XFreeFontNames(nameList);
  410.  
  411.     end:
  412.     fontPtr = AllocFont(tkFontPtr, tkwin, fontStructPtr, buf);
  413.     fontPtr->font.fa.underline  = faPtr->underline;
  414.     fontPtr->font.fa.overstrike = faPtr->overstrike;
  415.  
  416.     return (TkFont *) fontPtr;
  417. }
  418.  
  419.  
  420. /*
  421.  *---------------------------------------------------------------------------
  422.  *
  423.  * TkpDeleteFont --
  424.  *
  425.  *    Called to release a font allocated by TkpGetNativeFont() or
  426.  *    TkpGetFontFromAttributes().  The caller should have already
  427.  *    released the fields of the TkFont that are used exclusively by
  428.  *    the generic TkFont code.
  429.  *
  430.  * Results:
  431.  *    None.
  432.  *
  433.  * Side effects:
  434.  *    TkFont is deallocated.
  435.  *
  436.  *---------------------------------------------------------------------------
  437.  */
  438.  
  439. void
  440. TkpDeleteFont(tkFontPtr)
  441.     TkFont *tkFontPtr;        /* Token of font to be deleted. */
  442. {
  443.     UnixFont *fontPtr;
  444.  
  445.     fontPtr = (UnixFont *) tkFontPtr;
  446.  
  447.     XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
  448.     ckfree((char *) fontPtr);
  449. }
  450.  
  451. /*
  452.  *---------------------------------------------------------------------------
  453.  *
  454.  * TkpGetFontFamilies --
  455.  *
  456.  *    Return information about the font families that are available
  457.  *    on the display of the given window.
  458.  *
  459.  * Results:
  460.  *    interp->result is modified to hold a list of all the available
  461.  *    font families.
  462.  *
  463.  * Side effects:
  464.  *    None.
  465.  *
  466.  *---------------------------------------------------------------------------
  467.  */
  468.  
  469. void
  470. TkpGetFontFamilies(interp, tkwin)
  471.     Tcl_Interp *interp;
  472.     Tk_Window tkwin;
  473. {
  474.     int i, new, numNames;
  475.     char *family, *end, *p;
  476.     Tcl_HashTable familyTable;
  477.     Tcl_HashEntry *hPtr;
  478.     Tcl_HashSearch search;
  479.     char **nameList;
  480.  
  481.     Tcl_InitHashTable(&familyTable, TCL_STRING_KEYS);
  482.  
  483.     nameList = XListFonts(Tk_Display(tkwin), "*", 10000, &numNames);
  484.     for (i = 0; i < numNames; i++) {
  485.     if (nameList[i][0] != '-') {
  486.         continue;
  487.     }
  488.     family = strchr(nameList[i] + 1, '-');
  489.     if (family == NULL) {
  490.         continue;
  491.     }
  492.     family++;
  493.     end = strchr(family, '-');
  494.     if (end == NULL) {
  495.         continue;
  496.     }
  497.     *end = '\0';
  498.     for (p = family; *p != '\0'; p++) {
  499.         if (isupper(UCHAR(*p))) {
  500.         *p = tolower(UCHAR(*p));
  501.         }
  502.     }
  503.     Tcl_CreateHashEntry(&familyTable, family, &new);
  504.     }
  505.     XFree(nameList);
  506.  
  507.     hPtr = Tcl_FirstHashEntry(&familyTable, &search);
  508.     while (hPtr != NULL) {
  509.     Tcl_AppendElement(interp, Tcl_GetHashKey(&familyTable, hPtr));
  510.     hPtr = Tcl_NextHashEntry(&search);
  511.     }
  512.  
  513.     Tcl_DeleteHashTable(&familyTable);
  514. }
  515.  
  516. /*
  517.  *---------------------------------------------------------------------------
  518.  *
  519.  *  Tk_MeasureChars --
  520.  *
  521.  *    Determine the number of characters from the string that will fit
  522.  *    in the given horizontal span.  The measurement is done under the
  523.  *    assumption that Tk_DrawChars() will be used to actually display
  524.  *    the characters.
  525.  *
  526.  * Results:
  527.  *    The return value is the number of characters from source that
  528.  *    fit into the span that extends from 0 to maxLength.  *lengthPtr is
  529.  *    filled with the x-coordinate of the right edge of the last
  530.  *    character that did fit.
  531.  *
  532.  * Side effects:
  533.  *    None.
  534.  *
  535.  *---------------------------------------------------------------------------
  536.  */
  537. int
  538. Tk_MeasureChars(tkfont, source, numChars, maxLength, flags, lengthPtr)
  539.     Tk_Font tkfont;        /* Font in which characters will be drawn. */
  540.     CONST char *source;        /* Characters to be displayed.  Need not be
  541.                  * '\0' terminated. */
  542.     int numChars;        /* Maximum number of characters to consider
  543.                  * from source string. */
  544.     int maxLength;        /* If > 0, maxLength specifies the longest
  545.                  * permissible line length; don't consider any
  546.                  * character that would cross this
  547.                  * x-position.  If <= 0, then line length is
  548.                  * unbounded and the flags argument is
  549.                  * ignored. */
  550.     int flags;            /* Various flag bits OR-ed together:
  551.                  * TK_PARTIAL_OK means include the last char
  552.                  * which only partially fit on this line.
  553.                  * TK_WHOLE_WORDS means stop on a word
  554.                  * boundary, if possible.
  555.                  * TK_AT_LEAST_ONE means return at least one
  556.                  * character even if no characters fit. */
  557.     int *lengthPtr;        /* Filled with x-location just after the
  558.                  * terminating character. */
  559. {
  560.     UnixFont *fontPtr;
  561.     CONST char *p;        /* Current character. */
  562.     CONST char *term;        /* Pointer to most recent character that
  563.                  * may legally be a terminating character. */
  564.     int termX;            /* X-position just after term. */
  565.     int curX;            /* X-position corresponding to p. */
  566.     int newX;            /* X-position corresponding to p+1. */
  567.     int c, sawNonSpace;
  568.  
  569.     fontPtr = (UnixFont *) tkfont;
  570.  
  571.     if (numChars == 0) {
  572.     *lengthPtr = 0;
  573.     return 0;
  574.     }
  575.  
  576.     if (maxLength <= 0) {
  577.     maxLength = INT_MAX;
  578.     }
  579.  
  580.     newX = curX = termX = 0;
  581.     p = term = source;
  582.     sawNonSpace = !isspace(UCHAR(*p));
  583.  
  584.     /*
  585.      * Scan the input string one character at a time, calculating width.
  586.      */
  587.  
  588.     for (c = UCHAR(*p); ; ) {
  589.     newX += fontPtr->widths[c];
  590.     if (newX > maxLength) {
  591.         break;
  592.     }
  593.     curX = newX;
  594.     numChars--;
  595.     p++;
  596.     if (numChars == 0) {
  597.         term = p;
  598.         termX = curX;
  599.         break;
  600.     }
  601.  
  602.     c = UCHAR(*p);
  603.     if (isspace(c)) {
  604.         if (sawNonSpace) {
  605.         term = p;
  606.         termX = curX;
  607.         sawNonSpace = 0;
  608.         }
  609.     } else {
  610.         sawNonSpace = 1;
  611.     }
  612.     }
  613.  
  614.     /*
  615.      * P points to the first character that doesn't fit in the desired
  616.      * span.  Use the flags to figure out what to return.
  617.      */
  618.  
  619.     if ((flags & TK_PARTIAL_OK) && (numChars > 0) && (curX < maxLength)) {
  620.     /*
  621.      * Include the first character that didn't quite fit in the desired
  622.      * span.  The width returned will include the width of that extra
  623.      * character.
  624.      */
  625.  
  626.     numChars--;
  627.     curX = newX;
  628.     p++;
  629.     }
  630.     if ((flags & TK_AT_LEAST_ONE) && (term == source) && (numChars > 0)) {
  631.     term = p;
  632.     termX = curX;
  633.     if (term == source) {
  634.         term++;
  635.         termX = newX;
  636.     }
  637.     } else if ((numChars == 0) || !(flags & TK_WHOLE_WORDS)) {
  638.     term = p;
  639.     termX = curX;
  640.     }
  641.  
  642.     *lengthPtr = termX;
  643.     return term-source;
  644. }
  645.  
  646. /*
  647.  *---------------------------------------------------------------------------
  648.  *
  649.  * Tk_DrawChars, DrawChars --
  650.  *
  651.  *    Draw a string of characters on the screen.  Tk_DrawChars()
  652.  *    expands control characters that occur in the string to \X or
  653.  *    \xXX sequences.  DrawChars() just draws the strings.
  654.  *
  655.  * Results:
  656.  *    None.
  657.  *
  658.  * Side effects:
  659.  *    Information gets drawn on the screen.
  660.  *
  661.  *---------------------------------------------------------------------------
  662.  */
  663.  
  664. void
  665. Tk_DrawChars(display, drawable, gc, tkfont, source, numChars, x, y)
  666.     Display *display;        /* Display on which to draw. */
  667.     Drawable drawable;        /* Window or pixmap in which to draw. */
  668.     GC gc;            /* Graphics context for drawing characters. */
  669.     Tk_Font tkfont;        /* Font in which characters will be drawn;
  670.                  * must be the same as font used in GC. */
  671.     CONST char *source;        /* Characters to be displayed.  Need not be
  672.                  * '\0' terminated.  All Tk meta-characters
  673.                  * (tabs, control characters, and newlines)
  674.                  * should be stripped out of the string that
  675.                  * is passed to this function.  If they are
  676.                  * not stripped out, they will be displayed as
  677.                  * regular printing characters. */
  678.     int numChars;        /* Number of characters in string. */
  679.     int x, y;            /* Coordinates at which to place origin of
  680.                  * string when drawing. */
  681. {
  682.     UnixFont *fontPtr;
  683.     CONST char *p;
  684.     int i, type;
  685.     char buf[4];
  686.  
  687.     fontPtr = (UnixFont *) tkfont;
  688.  
  689.     p = source;
  690.     for (i = 0; i < numChars; i++) {
  691.     type = fontPtr->types[UCHAR(*p)];
  692.     if (type != NORMAL) {
  693.         DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y);
  694.         x += XTextWidth(fontPtr->fontStructPtr, source, p - source);
  695.         if (type == REPLACE) {
  696.         DrawChars(display, drawable, gc, fontPtr, buf,
  697.             GetControlCharSubst(UCHAR(*p), buf), x, y);
  698.         x += fontPtr->widths[UCHAR(*p)];
  699.         }
  700.         source = p + 1;
  701.     }
  702.     p++;
  703.     }
  704.  
  705.     DrawChars(display, drawable, gc, fontPtr, source, p - source, x, y);
  706. }
  707.  
  708. static void
  709. DrawChars(display, drawable, gc, fontPtr, source, numChars, x, y)
  710.     Display *display;        /* Display on which to draw. */
  711.     Drawable drawable;        /* Window or pixmap in which to draw. */
  712.     GC gc;            /* Graphics context for drawing characters. */
  713.     UnixFont *fontPtr;        /* Font in which characters will be drawn;
  714.                  * must be the same as font used in GC. */
  715.     CONST char *source;        /* Characters to be displayed.  Need not be
  716.                  * '\0' terminated.  All Tk meta-characters
  717.                  * (tabs, control characters, and newlines)
  718.                  * should be stripped out of the string that
  719.                  * is passed to this function.  If they are
  720.                  * not stripped out, they will be displayed as
  721.                  * regular printing characters. */
  722.     int numChars;        /* Number of characters in string. */
  723.     int x, y;            /* Coordinates at which to place origin of
  724.                  * string when drawing. */
  725. {        
  726.     XDrawString(display, drawable, gc, x, y, source, numChars);
  727.  
  728.     if (fontPtr->font.fa.underline != 0) {
  729.     XFillRectangle(display, drawable, gc, x,
  730.         y + fontPtr->underlinePos,
  731.         (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars),
  732.         (unsigned) fontPtr->barHeight);
  733.     }
  734.     if (fontPtr->font.fa.overstrike != 0) {
  735.     y -= fontPtr->font.fm.descent + (fontPtr->font.fm.ascent) / 10;
  736.     XFillRectangle(display, drawable, gc, x, y,
  737.         (unsigned) XTextWidth(fontPtr->fontStructPtr, source, numChars),
  738.         (unsigned) fontPtr->barHeight);
  739.     }
  740. }
  741.  
  742. /*
  743.  *---------------------------------------------------------------------------
  744.  *
  745.  * AllocFont --
  746.  *
  747.  *    Helper for TkpGetNativeFont() and TkpGetFontFromAttributes().
  748.  *    Allocates and intializes the memory for a new TkFont that
  749.  *    wraps the platform-specific data.
  750.  *
  751.  * Results:
  752.  *    Returns pointer to newly constructed TkFont.  
  753.  *
  754.  *    The caller is responsible for initializing the fields of the
  755.  *    TkFont that are used exclusively by the generic TkFont code, and
  756.  *    for releasing those fields before calling TkpDeleteFont().
  757.  *
  758.  * Side effects:
  759.  *    Memory allocated.
  760.  *
  761.  *---------------------------------------------------------------------------
  762.  */ 
  763.  
  764. static UnixFont *
  765. AllocFont(tkFontPtr, tkwin, fontStructPtr, fontName)
  766.     TkFont *tkFontPtr;        /* If non-NULL, store the information in
  767.                  * this existing TkFont structure, rather than
  768.                  * allocating a new structure to hold the
  769.                  * font; the existing contents of the font
  770.                  * will be released.  If NULL, a new TkFont
  771.                  * structure is allocated. */
  772.     Tk_Window tkwin;        /* For display where font will be used. */
  773.     XFontStruct *fontStructPtr;    /* X information about font. */
  774.     CONST char *fontName;    /* The string passed to XLoadQueryFont() to
  775.                  * construct the fontStructPtr. */
  776. {
  777.     UnixFont *fontPtr;
  778.     unsigned long value;
  779.     int i, width, firstChar, lastChar, n, replaceOK;
  780.     char *name, *p;
  781.     char buf[4];
  782.     TkXLFDAttributes xa;
  783.     double d;
  784.     
  785.     if (tkFontPtr != NULL) {
  786.     fontPtr = (UnixFont *) tkFontPtr;
  787.     XFreeFont(fontPtr->display, fontPtr->fontStructPtr);
  788.     } else {
  789.         fontPtr = (UnixFont *) ckalloc(sizeof(UnixFont));
  790.     }
  791.  
  792.     /*
  793.      * Encapsulate the generic stuff in the TkFont. 
  794.      */
  795.  
  796.     fontPtr->font.fid        = fontStructPtr->fid;
  797.  
  798.     if (XGetFontProperty(fontStructPtr, XA_FONT, &value) && (value != 0)) {
  799.     name = Tk_GetAtomName(tkwin, (Atom) value);
  800.     TkInitFontAttributes(&xa.fa);
  801.     if (TkParseXLFD(name, &xa) == TCL_OK) {
  802.         goto ok;
  803.     }
  804.     }
  805.     TkInitFontAttributes(&xa.fa);
  806.     if (TkParseXLFD(fontName, &xa) != TCL_OK) {
  807.     TkInitFontAttributes(&fontPtr->font.fa);
  808.     fontPtr->font.fa.family = Tk_GetUid(fontName);
  809.     } else {
  810.     ok:
  811.     fontPtr->font.fa = xa.fa;
  812.     }
  813.  
  814.     if (fontPtr->font.fa.pointsize < 0) {
  815.     d = -fontPtr->font.fa.pointsize * 72 / 25.4;
  816.     d *= WidthMMOfScreen(Tk_Screen(tkwin));
  817.     d /= WidthOfScreen(Tk_Screen(tkwin));
  818.     d += 0.5;
  819.     fontPtr->font.fa.pointsize = (int) d;
  820.     }
  821.     
  822.     fontPtr->font.fm.ascent    = fontStructPtr->ascent;
  823.     fontPtr->font.fm.descent    = fontStructPtr->descent;
  824.     fontPtr->font.fm.maxWidth    = fontStructPtr->max_bounds.width;
  825.     fontPtr->font.fm.fixed    = 1;
  826.     fontPtr->display        = Tk_Display(tkwin);
  827.     fontPtr->fontStructPtr    = fontStructPtr;
  828.  
  829.     /*
  830.      * Classify the characters.
  831.      */
  832.  
  833.     firstChar = fontStructPtr->min_char_or_byte2;
  834.     lastChar = fontStructPtr->max_char_or_byte2;
  835.     for (i = 0; i < 256; i++) {
  836.     if ((i == 0177) || (i < firstChar) || (i > lastChar)) {
  837.         fontPtr->types[i] = REPLACE;
  838.     } else {
  839.         fontPtr->types[i] = NORMAL;
  840.     }
  841.     }
  842.  
  843.     /*
  844.      * Compute the widths for all the normal characters.  Any other
  845.      * characters are given an initial width of 0.  Also, this determines
  846.      * if this is a fixed or variable width font, by comparing the widths
  847.      * of all the normal characters.
  848.      */
  849.  
  850.     width = 0;
  851.     for (i = 0; i < 256; i++) {
  852.     if (fontPtr->types[i] != NORMAL) {
  853.         n = 0;
  854.     } else if (fontStructPtr->per_char == NULL) {
  855.         n = fontStructPtr->max_bounds.width;
  856.     } else {
  857.         n = fontStructPtr->per_char[i - firstChar].width;
  858.     }
  859.     fontPtr->widths[i] = n;
  860.     if (n != 0) {
  861.         if (width == 0) {
  862.         width = n;
  863.         } else if (width != n) {
  864.         fontPtr->font.fm.fixed = 0;
  865.         }
  866.     }
  867.     }
  868.  
  869.     /*
  870.      * Compute the widths of the characters that should be replaced with
  871.      * control character expansions.  If the appropriate chars are not
  872.      * available in this font, then control character expansions will not
  873.      * be used; control chars will be invisible & zero-width.
  874.      */
  875.  
  876.     replaceOK = 1;
  877.     for (p = hexChars; *p != '\0'; p++) {
  878.     if ((UCHAR(*p) < firstChar) || (UCHAR(*p) > lastChar)) {
  879.         replaceOK = 0;
  880.         break;
  881.     }
  882.     }
  883.     for (i = 0; i < 256; i++) {
  884.     if (fontPtr->types[i] == REPLACE) {
  885.         if (replaceOK) {
  886.         n = GetControlCharSubst(i, buf);
  887.         for ( ; --n >= 0; ) {
  888.             fontPtr->widths[i] += fontPtr->widths[UCHAR(buf[n])];
  889.         }
  890.         } else {
  891.         fontPtr->types[i] = SKIP;
  892.         }
  893.     }
  894.     }
  895.  
  896.     if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_POSITION, &value)) {
  897.     fontPtr->underlinePos = value;
  898.     } else {
  899.     /*
  900.      * If the XA_UNDERLINE_POSITION property does not exist, the X
  901.      * manual recommends using the following value:
  902.      */
  903.  
  904.     fontPtr->underlinePos = fontStructPtr->descent / 2;
  905.     }
  906.     fontPtr->barHeight = 0;
  907.     if (XGetFontProperty(fontStructPtr, XA_UNDERLINE_THICKNESS, &value)) {
  908.     /*
  909.      * Sometimes this is 0 even though it shouldn't be.
  910.      */
  911.     fontPtr->barHeight = value;
  912.     }
  913.     if (fontPtr->barHeight == 0) {
  914.     /*
  915.      * If the XA_UNDERLINE_THICKNESS property does not exist, the X
  916.      * manual recommends using the width of the stem on a capital
  917.      * letter.  I don't know of a way to get the stem width of a letter,
  918.      * so guess and use 1/3 the width of a capital I.
  919.      */
  920.  
  921.     fontPtr->barHeight = fontPtr->widths['I'] / 3;
  922.     if (fontPtr->barHeight == 0) {
  923.         fontPtr->barHeight = 1;
  924.     }
  925.     }
  926.     if (fontPtr->underlinePos + fontPtr->barHeight > fontStructPtr->descent) {
  927.     /*
  928.      * If this set of cobbled together values would cause the bottom of
  929.      * the underline bar to stick below the descent of the font, jack
  930.      * the underline up a bit higher.
  931.      */
  932.  
  933.     fontPtr->barHeight = fontStructPtr->descent - fontPtr->underlinePos;
  934.     if (fontPtr->barHeight == 0) {
  935.         fontPtr->underlinePos--;
  936.         fontPtr->barHeight = 1;
  937.     }
  938.     }
  939.  
  940.     return fontPtr;
  941. }
  942.  
  943. /*
  944.  *---------------------------------------------------------------------------
  945.  *
  946.  * GetControlCharSubst --
  947.  *
  948.  *    When displaying text in a widget, a backslashed escape sequence
  949.  *    is substituted for control characters that occur in the text.
  950.  *    Given a control character, fill in a buffer with the replacement
  951.  *    string that should be displayed.
  952.  *
  953.  * Results:
  954.  *    The return value is the length of the substitute string.  buf is
  955.  *    filled with the substitute string; it is not '\0' terminated.
  956.  *
  957.  * Side effects:
  958.  *    None.
  959.  *
  960.  *---------------------------------------------------------------------------
  961.  */
  962.  
  963. static int
  964. GetControlCharSubst(c, buf)
  965.     int        c;        /* The control character to be replaced. */
  966.     char    buf[4];        /* Buffer that gets replacement string.  It
  967.                  * only needs to be 4 characters long. */
  968. {
  969.     buf[0] = '\\';
  970.     if ((c < sizeof(mapChars)) && (mapChars[c] != 0)) {
  971.     buf[1] = mapChars[c];
  972.     return 2;
  973.     } else {
  974.     buf[1] = 'x';
  975.     buf[2] = hexChars[(c >> 4) & 0xf];
  976.     buf[3] = hexChars[c & 0xf];
  977.     return 4;
  978.     }
  979. }
  980.